package com.example.service.impl;

import com.example.common.Result;
import com.example.dto.WorkScheduleDTO;
import com.example.entity.WorkSchedule;
import com.example.mapper.WorkScheduleMapper;
import com.example.service.WorkScheduleService;
import com.example.util.UserContextUtil;
import com.example.vo.WorkScheduleVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 排班服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkScheduleServiceImpl implements WorkScheduleService {
    
    private final WorkScheduleMapper workScheduleMapper;
    private final UserContextUtil userContextUtil;
    
    // 星期几名称映射
    private static final Map<Integer, String> DAY_OF_WEEK_NAMES = Map.of(
        1, "周一", 2, "周二", 3, "周三", 4, "周四", 
        5, "周五", 6, "周六", 7, "周日"
    );
    
    @Override
    @Transactional
    public Result<Void> addWorkSchedule(WorkScheduleDTO workScheduleDTO) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 参数校验
            Result<Void> validationResult = validateWorkScheduleDTO(workScheduleDTO);
            if (!validationResult.isSuccess()) {
                return validationResult;
            }
            
            // 检查时间段是否冲突
            int conflictCount = workScheduleMapper.checkTimeConflict(
                storeManagerId, workScheduleDTO.getDayOfWeek(),
                workScheduleDTO.getStartHour(), workScheduleDTO.getEndHour(), null
            );
            if (conflictCount > 0) {
                return Result.error("该时间段与现有排班冲突");
            }
            
            // 创建排班记录
            WorkSchedule workSchedule = new WorkSchedule();
            workSchedule.setStoreManagerId(storeManagerId);
            workSchedule.setDayOfWeek(workScheduleDTO.getDayOfWeek());
            workSchedule.setStartHour(workScheduleDTO.getStartHour());
            workSchedule.setEndHour(workScheduleDTO.getEndHour());
            workSchedule.setMaxAppointments(workScheduleDTO.getMaxAppointments());
            workSchedule.setStatus(workScheduleDTO.getStatus() != null ? workScheduleDTO.getStatus() : 1);
            workSchedule.setRemark(workScheduleDTO.getRemark());
            workSchedule.setCreateTime(LocalDateTime.now());
            workSchedule.setUpdateTime(LocalDateTime.now());
            workSchedule.setDeleted(0);
            
            int result = workScheduleMapper.insert(workSchedule);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("添加排班失败");
            }
        } catch (Exception e) {
            log.error("添加排班失败", e);
            return Result.error("添加排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> updateWorkSchedule(Long id, WorkScheduleDTO workScheduleDTO) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 检查排班是否存在
            WorkSchedule existingSchedule = workScheduleMapper.selectById(id);
            if (existingSchedule == null || existingSchedule.getDeleted() == 1) {
                return Result.error("排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!existingSchedule.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限修改此排班");
            }
            
            // 参数校验
            Result<Void> validationResult = validateWorkScheduleDTO(workScheduleDTO);
            if (!validationResult.isSuccess()) {
                return validationResult;
            }
            
            // 检查时间段是否冲突（排除当前记录）
            int conflictCount = workScheduleMapper.checkTimeConflict(
                storeManagerId, workScheduleDTO.getDayOfWeek(),
                workScheduleDTO.getStartHour(), workScheduleDTO.getEndHour(), id
            );
            if (conflictCount > 0) {
                return Result.error("该时间段与现有排班冲突");
            }
            
            // 更新排班记录
            WorkSchedule workSchedule = new WorkSchedule();
            workSchedule.setId(id);
            workSchedule.setDayOfWeek(workScheduleDTO.getDayOfWeek());
            workSchedule.setStartHour(workScheduleDTO.getStartHour());
            workSchedule.setEndHour(workScheduleDTO.getEndHour());
            workSchedule.setMaxAppointments(workScheduleDTO.getMaxAppointments());
            workSchedule.setStatus(workScheduleDTO.getStatus());
            workSchedule.setRemark(workScheduleDTO.getRemark());
            workSchedule.setUpdateTime(LocalDateTime.now());
            
            int result = workScheduleMapper.updateById(workSchedule);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("更新排班失败");
            }
        } catch (Exception e) {
            log.error("更新排班失败", e);
            return Result.error("更新排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> deleteWorkSchedule(Long id) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            // 检查排班是否存在
            WorkSchedule existingSchedule = workScheduleMapper.selectById(id);
            if (existingSchedule == null || existingSchedule.getDeleted() == 1) {
                return Result.error("排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!existingSchedule.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限删除此排班");
            }
            
            int result = workScheduleMapper.deleteById(id);
            if (result > 0) {
                return Result.success();
            } else {
                return Result.error("删除排班失败");
            }
        } catch (Exception e) {
            log.error("删除排班失败", e);
            return Result.error("删除排班失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<WorkScheduleVO> getWorkScheduleById(Long id) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            WorkSchedule workSchedule = workScheduleMapper.selectById(id);
            if (workSchedule == null || workSchedule.getDeleted() == 1) {
                return Result.error("排班记录不存在");
            }
            
            // 检查是否是当前店长的排班
            if (!workSchedule.getStoreManagerId().equals(storeManagerId)) {
                return Result.error("无权限查看此排班");
            }
            
            WorkScheduleVO vo = convertToVO(workSchedule);
            return Result.success(vo);
        } catch (Exception e) {
            log.error("查询排班详情失败", e);
            return Result.error("查询排班详情失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<WorkScheduleVO>> getMyWorkSchedules() {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            List<WorkSchedule> schedules = workScheduleMapper.selectByStoreManagerId(storeManagerId);
            List<WorkScheduleVO> vos = schedules.stream()
                .map(this::convertToVO)
                .sorted(Comparator.comparing(WorkScheduleVO::getDayOfWeek)
                    .thenComparing(WorkScheduleVO::getStartHour))
                .collect(Collectors.toList());
            
            return Result.success(vos);
        } catch (Exception e) {
            log.error("查询我的排班列表失败", e);
            return Result.error("查询我的排班列表失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<WorkScheduleVO>> getMyWorkSchedulesByDay(Integer dayOfWeek) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (dayOfWeek == null || dayOfWeek < 1 || dayOfWeek > 7) {
                return Result.error("星期几参数错误");
            }
            
            List<WorkSchedule> schedules = workScheduleMapper.selectByStoreManagerIdAndDayOfWeek(storeManagerId, dayOfWeek);
            List<WorkScheduleVO> vos = schedules.stream()
                .map(this::convertToVO)
                .sorted(Comparator.comparing(WorkScheduleVO::getStartHour))
                .collect(Collectors.toList());
            
            return Result.success(vos);
        } catch (Exception e) {
            log.error("查询指定日期排班列表失败", e);
            return Result.error("查询指定日期排班列表失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<List<WorkScheduleVO>>> getMyWeeklySchedule() {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            List<WorkSchedule> allSchedules = workScheduleMapper.selectByStoreManagerId(storeManagerId);
            
            // 按星期几分组
            Map<Integer, List<WorkSchedule>> schedulesByDay = allSchedules.stream()
                .collect(Collectors.groupingBy(WorkSchedule::getDayOfWeek));
            
            // 构建周排班表（7天）
            List<List<WorkScheduleVO>> weeklySchedule = new ArrayList<>();
            for (int day = 1; day <= 7; day++) {
                List<WorkSchedule> daySchedules = schedulesByDay.getOrDefault(day, new ArrayList<>());
                List<WorkScheduleVO> dayVOs = daySchedules.stream()
                    .map(this::convertToVO)
                    .sorted(Comparator.comparing(WorkScheduleVO::getStartHour))
                    .collect(Collectors.toList());
                weeklySchedule.add(dayVOs);
            }
            
            return Result.success(weeklySchedule);
        } catch (Exception e) {
            log.error("查询周排班表失败", e);
            return Result.error("查询周排班表失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> batchSetWorkSchedules(List<WorkScheduleDTO> workScheduleDTOs) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (workScheduleDTOs == null || workScheduleDTOs.isEmpty()) {
                return Result.error("排班数据不能为空");
            }
            
            // 逐个添加排班
            for (WorkScheduleDTO dto : workScheduleDTOs) {
                Result<Void> result = addWorkSchedule(dto);
                if (!result.isSuccess()) {
                    return result; // 如果有任何一个失败，直接返回错误
                }
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("批量设置排班失败", e);
            return Result.error("批量设置排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> copyScheduleToOtherDays(Integer fromDay, List<Integer> toDays) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (fromDay == null || fromDay < 1 || fromDay > 7) {
                return Result.error("源星期几参数错误");
            }
            
            if (toDays == null || toDays.isEmpty()) {
                return Result.error("目标星期几不能为空");
            }
            
            // 获取源日期的排班
            List<WorkSchedule> sourceSchedules = workScheduleMapper.selectByStoreManagerIdAndDayOfWeek(storeManagerId, fromDay);
            if (sourceSchedules.isEmpty()) {
                return Result.error("源日期没有排班数据");
            }
            
            // 复制到目标日期
            for (Integer toDay : toDays) {
                if (toDay < 1 || toDay > 7) {
                    continue; // 跳过无效的星期几
                }
                
                for (WorkSchedule sourceSchedule : sourceSchedules) {
                    // 检查目标日期是否已有冲突的排班
                    int conflictCount = workScheduleMapper.checkTimeConflict(
                        storeManagerId, toDay,
                        sourceSchedule.getStartHour(), sourceSchedule.getEndHour(), null
                    );
                    
                    if (conflictCount == 0) {
                        // 创建新的排班记录
                        WorkSchedule newSchedule = new WorkSchedule();
                        newSchedule.setStoreManagerId(storeManagerId);
                        newSchedule.setDayOfWeek(toDay);
                        newSchedule.setStartHour(sourceSchedule.getStartHour());
                        newSchedule.setEndHour(sourceSchedule.getEndHour());
                        newSchedule.setMaxAppointments(sourceSchedule.getMaxAppointments());
                        newSchedule.setStatus(sourceSchedule.getStatus());
                        newSchedule.setRemark(sourceSchedule.getRemark());
                        newSchedule.setCreateTime(LocalDateTime.now());
                        newSchedule.setUpdateTime(LocalDateTime.now());
                        newSchedule.setDeleted(0);
                        
                        workScheduleMapper.insert(newSchedule);
                    }
                }
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("复制排班失败", e);
            return Result.error("复制排班失败：" + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Result<Void> clearScheduleByDay(Integer dayOfWeek) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (dayOfWeek == null || dayOfWeek < 1 || dayOfWeek > 7) {
                return Result.error("星期几参数错误");
            }
            
            // 获取该天的所有排班
            List<WorkSchedule> schedules = workScheduleMapper.selectByStoreManagerIdAndDayOfWeek(storeManagerId, dayOfWeek);
            
            // 逻辑删除所有排班
            for (WorkSchedule schedule : schedules) {
                workScheduleMapper.deleteById(schedule.getId());
            }
            
            return Result.success();
        } catch (Exception e) {
            log.error("清空排班失败", e);
            return Result.error("清空排班失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<Integer[]>> getOccupiedTimeSlots(Integer dayOfWeek) {
        try {
            // 获取当前用户ID（店长ID）
            Long storeManagerId = userContextUtil.getCurrentUserId();
            if (storeManagerId == null) {
                return Result.error("用户未登录");
            }
            
            if (dayOfWeek == null || dayOfWeek < 1 || dayOfWeek > 7) {
                return Result.error("星期几参数错误");
            }
            
            // 获取该天的所有排班
            List<WorkSchedule> schedules = workScheduleMapper.selectByStoreManagerIdAndDayOfWeek(storeManagerId, dayOfWeek);
            
            // 转换为时间段数组
            List<Integer[]> occupiedSlots = schedules.stream()
                .map(schedule -> new Integer[]{schedule.getStartHour(), schedule.getEndHour()})
                .collect(Collectors.toList());
            
            return Result.success(occupiedSlots);
        } catch (Exception e) {
            log.error("获取已排班时间段失败", e);
            return Result.error("获取已排班时间段失败：" + e.getMessage());
        }
    }
    
    /**
     * 参数校验
     */
    private Result<Void> validateWorkScheduleDTO(WorkScheduleDTO dto) {
        if (dto.getDayOfWeek() == null || dto.getDayOfWeek() < 1 || dto.getDayOfWeek() > 7) {
            return Result.error("星期几参数错误，应为1-7");
        }
        
        if (dto.getStartHour() == null || dto.getStartHour() < 8 || dto.getStartHour() > 20) {
            return Result.error("开始时间参数错误，应为8-20");
        }
        
        if (dto.getEndHour() == null || dto.getEndHour() < 8 || dto.getEndHour() > 20) {
            return Result.error("结束时间参数错误，应为8-20");
        }
        
        if (dto.getStartHour() >= dto.getEndHour()) {
            return Result.error("开始时间必须小于结束时间");
        }
        
        if (dto.getMaxAppointments() == null || dto.getMaxAppointments() < 1) {
            return Result.error("可预约人数必须大于0");
        }
        
        return Result.success();
    }
    
    /**
     * 转换为VO
     */
    private WorkScheduleVO convertToVO(WorkSchedule workSchedule) {
        WorkScheduleVO vo = new WorkScheduleVO();
        vo.setId(workSchedule.getId());
        vo.setStoreManagerId(workSchedule.getStoreManagerId());
        vo.setDayOfWeek(workSchedule.getDayOfWeek());
        vo.setDayOfWeekName(DAY_OF_WEEK_NAMES.get(workSchedule.getDayOfWeek()));
        vo.setStartHour(workSchedule.getStartHour());
        vo.setEndHour(workSchedule.getEndHour());
        vo.setTimeRange(workSchedule.getStartHour() + ":00-" + workSchedule.getEndHour() + ":00");
        vo.setMaxAppointments(workSchedule.getMaxAppointments());
        vo.setStatus(workSchedule.getStatus());
        vo.setStatusName(workSchedule.getStatus() == 1 ? "启用" : "禁用");
        vo.setRemark(workSchedule.getRemark());
        vo.setCreateTime(workSchedule.getCreateTime());
        vo.setUpdateTime(workSchedule.getUpdateTime());
        return vo;
    }
} 